package com.auction.service.impl;

import com.auction.dto.BidDTO;
import com.auction.dto.BidPageQueryDTO;
import com.auction.exception.BusinessException;
import com.auction.mapper.AuctionMapper;
import com.auction.mapper.BidMapper;
import com.auction.pojo.Auction;
import com.auction.pojo.Bid;
import com.auction.pojo.PageResult;
import com.auction.service.AuctionService;
import com.auction.service.BidService;
import com.auction.vo.BidVO;
import com.auction.vo.BidWithTitle;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class BidServiceImpl implements BidService {

    @Autowired
    private BidMapper bidMapper;

    @Autowired
    private AuctionMapper auctionMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 获取拍卖品的所有竞价记录
     *
     * @param auctionId
     * @return
     */
    @Override
    public List<Bid> getByAuctionId(Long auctionId) {
        return bidMapper.selectByAuctionId(auctionId);
    }

    /**
     * 获取拍卖品的最高竞价记录
     *
     * @param auctionId
     * @return
     */
    @Override
    public Bid getHighestBid(Long auctionId) {
        // 先从Redis缓存中获取
        String highestBidKey = "auction:" + auctionId + ":highest_bid";
        Bid highestBid = (Bid) redisTemplate.opsForValue().get(highestBidKey);

        // 如果缓存中没有，从数据库查询
        if (highestBid == null) {
            highestBid = bidMapper.selectHighestBid(auctionId);

            // 如果数据库中有数据，则缓存
            if (highestBid != null) {
                // 获取拍卖结束时间
                Auction auction = auctionMapper.selectById(auctionId);
                if (auction != null) {
                    // 缓存数据
                    redisTemplate.opsForValue().set(highestBidKey, highestBid);

                    // 设置过期时间为拍卖结束时间
                    long ttl = java.time.Duration.between(LocalDateTime.now(), auction.getEndTime()).getSeconds();
                    if (ttl > 0) {
                        redisTemplate.expire(highestBidKey, ttl, TimeUnit.SECONDS);
                    }
                }
            }
        }

        return highestBid;
    }

    /**
     * 分页查询用户的竞价记录，并将拍卖品标题作为VO的属性
     * @param pageNum
     * @param pageSize
     * @param userId
     * @return
     */
    @Override
    public PageInfo<BidWithTitle> page(int pageNum, int pageSize, Long userId) {
        // 分页查询
        PageHelper.startPage(pageNum, pageSize);
        // 查询用户的竞价记录
        List<BidWithTitle> list = bidMapper.pageByUserIdWithTitle(userId);
        list.forEach(bid -> bid.setTitle(auctionMapper.selectById(bid.getAuctionId()).getTitle()));

        return new PageInfo<>(list);
    }

    /**
     * 分页查询所有竞价记录
     * @param bidPageQueryDTO
     * @return
     */
    @Override
    public PageResult pageQuery(BidPageQueryDTO bidPageQueryDTO) {
        PageHelper.startPage(bidPageQueryDTO.getPage(), bidPageQueryDTO.getPageSize());
        Page<BidVO> page = bidMapper.pageQuery(bidPageQueryDTO);

        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 分页查询用户的竞价记录
     *
     * @param pageNum
     * @param pageSize
     * @param userId
     * @return
     */
    @Override
    public PageInfo<Bid> pageByUserId(int pageNum, int pageSize, Long userId) {
        // 分页查询
        PageHelper.startPage(pageNum, pageSize);

        // 查询用户的竞价记录
        List<Bid> list = bidMapper.selectByUserId(userId);

        return new PageInfo<>(list);
    }

    /**
     * 提交竞价
     * 
     * @param bidDTO
     * @param userId
     * @return
     */
    @Override
    @Transactional
    public boolean bid(BidDTO bidDTO, Long userId) {
        // 获取拍卖品信息
        Auction auction = auctionMapper.selectById(bidDTO.getAuctionId());

        // 验证拍卖品是否存在
        if (auction == null) {
            throw new BusinessException("拍卖品不存在");
        }

        // 验证拍卖品状态是否为活跃
        if (!"ACTIVE".equals(auction.getStatus())) {
            throw new BusinessException("拍卖品不在竞拍状态");
        }

        // 验证拍卖时间是否有效
        LocalDateTime now = LocalDateTime.now();
        if (now.isBefore(auction.getStartTime()) || now.isAfter(auction.getEndTime())) {
            throw new BusinessException("不在拍卖时间内");
        }

        // 从Redis获取当前价格
        String auctionPriceKey = "auction:" + bidDTO.getAuctionId() + ":current_price";
        BigDecimal currentPrice = (BigDecimal) redisTemplate.opsForValue().get(auctionPriceKey);

        // 如果Redis中没有，则使用数据库中的价格
        if (currentPrice == null) {
            currentPrice = auction.getStartPrice();
            Bid highestBid = bidMapper.selectHighestBid(bidDTO.getAuctionId());
            if (highestBid != null) {
                currentPrice = highestBid.getBidPrice();
            }
        }

        // 验证出价是否大于当前价格
        if (bidDTO.getBidPrice().compareTo(currentPrice) <= 0) {
            throw new BusinessException("出价必须高于当前价格");
        }

        // 验证卖家不能对自己的拍卖品出价
        if (auction.getSellerId().equals(userId)) {
            throw new BusinessException("卖家不能对自己的拍卖品出价");
        }

        // 创建竞价记录
        Bid bid = new Bid();
        bid.setAuctionId(bidDTO.getAuctionId());
        bid.setUserId(userId);
        bid.setBidPrice(bidDTO.getBidPrice());
        bid.setBidTime(now);
        bid.setStatus(0); // 0表示领先
        bid.setCreateTime(now);
        bid.setUpdateTime(now);

        // 将之前的竞价状态设置为无效
        bidMapper.updatePreviousBidsStatus(bidDTO.getAuctionId(), 1); // 1表示被超越

        // 插入新的竞价记录
        bidMapper.insert(bid);

        // 更新拍卖品当前价格
        auctionMapper.updateCurrentPrice(bidDTO.getAuctionId(), bidDTO.getBidPrice());

        // 更新Redis缓存
        // 1. 更新当前价格
        redisTemplate.opsForValue().set(auctionPriceKey, bidDTO.getBidPrice());

        // 2. 更新最高竞价记录
        String highestBidKey = "auction:" + bidDTO.getAuctionId() + ":highest_bid";
        redisTemplate.opsForValue().set(highestBidKey, bid);

        // 3. 将竞价加入竞价列表
        String bidListKey = "auction:" + bidDTO.getAuctionId() + ":bids";
        redisTemplate.opsForList().leftPush(bidListKey, bid);

        // 设置过期时间为拍卖结束时间
        long ttl = java.time.Duration.between(now, auction.getEndTime()).getSeconds();
        if (ttl > 0) {
            redisTemplate.expire(auctionPriceKey, ttl, TimeUnit.SECONDS);
            redisTemplate.expire(highestBidKey, ttl, TimeUnit.SECONDS);
            redisTemplate.expire(bidListKey, ttl, TimeUnit.SECONDS);
        }

        log.info("用户{}竞价成功，拍卖品ID：{}，价格：{}", userId, bidDTO.getAuctionId(), bidDTO.getBidPrice());

        return true;
    }
}